package com.pcbly.web.components.utils;

import java.io.IOException;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import com.opensymphony.xwork2.LocaleProvider;
import com.pcbly.web.bean.user.UserBean;
import com.pcbly.web.components.utils.property.OfficeGlobals;
import com.pcbly.web.components.utils.provider.OfficeTextProvider;

@SuppressWarnings("unchecked")
public class LocaleUtils {
	private static final Logger log = LogManager.getLogger(LocaleUtils.class);
	private static final Map timeZoneLists = Collections
			.synchronizedMap(new HashMap());
	private static final Map calendarLocaleFormatMap = new HashMap();
	private static final String DEFAULT_JS_DATE_FORMAT = "%d/%m/%Y";
	private static final String I18N_PROPERTY_FILE_PREFIX = "office_i18n";
	public static final List SUPPORTED_LOCALES = Collections
			.unmodifiableList(getSupportedLocales());
	public static final Map<String, String> I18N_EDITION_KEYS = getContainerKeys();
	private static final Map<String, String> languageMap;
	private static final Map<String, String> calendarLocaleMap;
	private static final String DEFAULT_CALENDAR_LOCALE_CODE = "en";
	private static String timeZoneIds[] = { "GMT", "Pacific/Apia", "HST",
			"AST", "America/Los_Angeles", "America/Phoenix",
			"America/Mazatlan", "America/Denver", "America/Belize",
			"America/Chicago", "America/Mexico_City", "America/Regina",
			"America/Bogota", "America/New_York", "America/Indianapolis",
			"America/Halifax", "America/Caracas", "America/Santiago",
			"America/St_Johns", "America/Sao_Paulo", "America/Buenos_Aires",
			"America/Godthab", "Atlantic/South_Georgia", "Atlantic/Azores",
			"Atlantic/Cape_Verde", "Africa/Casablanca", "Europe/Dublin",
			"Europe/Berlin", "Europe/Belgrade", "Europe/Paris",
			"Europe/Warsaw", "ECT", "Europe/Athens", "Europe/Bucharest",
			"Africa/Cairo", "Africa/Harare", "Europe/Helsinki",
			"Asia/Jerusalem", "Asia/Baghdad", "Asia/Kuwait", "Europe/Moscow",
			"Africa/Nairobi", "Asia/Tehran", "Asia/Muscat", "Asia/Baku",
			"Asia/Kabul", "Asia/Yekaterinburg", "Asia/Karachi",
			"Asia/Calcutta", "Asia/Katmandu", "Asia/Almaty", "Asia/Dhaka",
			"Asia/Colombo", "Asia/Rangoon", "Asia/Bangkok", "Asia/Krasnoyarsk",
			"Asia/Hong_Kong", "Asia/Irkutsk", "Asia/Kuala_Lumpur",
			"Australia/Perth", "Asia/Taipei", "Asia/Tokyo", "Asia/Seoul",
			"Asia/Yakutsk", "Australia/Adelaide", "Australia/Darwin",
			"Australia/Brisbane", "Australia/Sydney", "Pacific/Guam",
			"Australia/Hobart", "Asia/Vladivostok", "Pacific/Noumea",
			"Pacific/Auckland", "Pacific/Fiji", "Pacific/Tongatapu" };
	private static final Map<String, String> nameMap;
	private static Map cachedCandidateLocales = new HashMap();

	static {
		languageMap = new HashMap<String, String>();
		languageMap.put("aa", "Afar");
		languageMap.put("ab", "Abkhazian");
		languageMap.put("af", "Afrikaans");
		languageMap.put("am", "Amharic");
		languageMap.put("ar", "Arabic");
		languageMap.put("as", "Assamese");
		languageMap.put("ay", "Aymara");
		languageMap.put("az", "Azerbaijani");
		languageMap.put("ba", "Bashkir");
		languageMap.put("be", "Byelorussian");
		languageMap.put("bg", "Bulgarian");
		languageMap.put("bh", "Bihari");
		languageMap.put("bi", "Bislama");
		languageMap.put("bn", "Bengali; Bangla");
		languageMap.put("bo", "Tibetan");
		languageMap.put("br", "Breton");
		languageMap.put("ca", "Catalan");
		languageMap.put("co", "Corsican");
		languageMap.put("cs", "Czech");
		languageMap.put("cy", "Welsh");
		languageMap.put("da", "Danish");
		languageMap.put("de", "German");
		languageMap.put("dz", "Bhutani");
		languageMap.put("el", "Greek");
		languageMap.put(DEFAULT_CALENDAR_LOCALE_CODE, "English");
		languageMap.put("eo", "Esperanto");
		languageMap.put("es", "Spanish");
		languageMap.put("et", "Estonian");
		languageMap.put("eu", "Basque");
		languageMap.put("fa", "Persian");
		languageMap.put("fi", "Finnish");
		languageMap.put("fj", "Fiji");
		languageMap.put("fo", "Faroese");
		languageMap.put("fr", "French");
		languageMap.put("fy", "Frisian");
		languageMap.put("ga", "Irish");
		languageMap.put("gd", "Scots Gaelic");
		languageMap.put("gl", "Galician");
		languageMap.put("gn", "Guarani");
		languageMap.put("gu", "Gujarati");
		languageMap.put("ha", "Hausa");
		languageMap.put("he", "Hebrew");
		languageMap.put("hi", "Hindi");
		languageMap.put("hr", "Croatian");
		languageMap.put("hu", "Hungarian");
		languageMap.put("hy", "Armenian");
		languageMap.put("ia", "Interlingua");
		languageMap.put("id", "Indonesian");
		languageMap.put("ie", "Interlingue");
		languageMap.put("ik", "Inupiak");
		languageMap.put("is", "Icelandic");
		languageMap.put("it", "Italian");
		languageMap.put("iu", "Inuktitut");
		languageMap.put("ja", "Japanese");
		languageMap.put("jw", "Javanese");
		languageMap.put("ka", "Georgian");
		languageMap.put("kk", "Kazakh");
		languageMap.put("kl", "Greenlandic");
		languageMap.put("km", "Cambodian");
		languageMap.put("kn", "Kannada");
		languageMap.put("ko", "Korean");
		languageMap.put("ks", "Kashmiri");
		languageMap.put("ku", "Kurdish");
		languageMap.put("ky", "Kirghiz");
		languageMap.put("la", "Latin");
		languageMap.put("ln", "Lingala");
		languageMap.put("lo", "Laothian");
		languageMap.put("lt", "Lithuanian");
		languageMap.put("lv", "Latvian, Lettish");
		languageMap.put("mg", "Malagasy");
		languageMap.put("mi", "Maori");
		languageMap.put("mk", "Macedonian");
		languageMap.put("ml", "Malayalam");
		languageMap.put("mn", "Mongolian");
		languageMap.put("mo", "Moldavian");
		languageMap.put("mr", "Marathi");
		languageMap.put("ms", "Malay");
		languageMap.put("mt", "Maltese");
		languageMap.put("my", "Burmese");
		languageMap.put("na", "Nauru");
		languageMap.put("ne", "Nepali");
		languageMap.put("nl", "Dutch");
		languageMap.put("no", "Norwegian");
		languageMap.put("oc", "Occitan");
		languageMap.put("om", "(Afan) Oromo");
		languageMap.put("or", "Oriya");
		languageMap.put("pa", "Punjabi");
		languageMap.put("pl", "Polish");
		languageMap.put("ps", "Pashto, Pushto");
		languageMap.put("pt", "Portuguese");
		languageMap.put("qu", "Quechua");
		languageMap.put("rm", "Rhaeto-Romance");
		languageMap.put("rn", "Kirundi");
		languageMap.put("ro", "Romanian");
		languageMap.put("ru", "Russian");
		languageMap.put("rw", "Kinyarwanda");
		languageMap.put("sa", "Sanskrit");
		languageMap.put("sd", "Sindhi");
		languageMap.put("sg", "Sangho");
		languageMap.put("sh", "Serbo-Croatian");
		languageMap.put("si", "Sinhalese");
		languageMap.put("sk", "Slovak");
		languageMap.put("sl", "Slovenian");
		languageMap.put("sm", "Samoan");
		languageMap.put("sn", "Shona");
		languageMap.put("so", "Somali");
		languageMap.put("sq", "Albanian");
		languageMap.put("sr", "Serbian");
		languageMap.put("ss", "Siswati");
		languageMap.put("st", "Sesotho");
		languageMap.put("su", "Sundanese");
		languageMap.put("sv", "Swedish");
		languageMap.put("sw", "Swahili");
		languageMap.put("ta", "Tamil");
		languageMap.put("te", "Telugu");
		languageMap.put("tg", "Tajik");
		languageMap.put("th", "Thai");
		languageMap.put("ti", "Tigrinya");
		languageMap.put("tk", "Turkmen");
		languageMap.put("tl", "Tagalog");
		languageMap.put("tn", "Setswana");
		languageMap.put("to", "Tonga");
		languageMap.put("tr", "Turkish");
		languageMap.put("ts", "Tsonga");
		languageMap.put("tt", "Tatar");
		languageMap.put("tw", "Twi");
		languageMap.put("ug", "Uighur");
		languageMap.put("uk", "Ukrainian");
		languageMap.put("ur", "Urdu");
		languageMap.put("uz", "Uzbek");
		languageMap.put("vi", "Vietnamese");
		languageMap.put("vo", "Volapuk");
		languageMap.put("wo", "Wolof");
		languageMap.put("xh", "Xhosa");
		languageMap.put("yi", "Yiddish");
		languageMap.put("yo", "Yoruba");
		languageMap.put("za", "Zhuang");
		languageMap.put("zh", "Chinese");
		languageMap.put("zu", "Zulu");
		calendarLocaleMap = new HashMap<String, String>();
		calendarLocaleMap.put("al", "calendar-al.js");
		calendarLocaleMap.put("af", "calendar-af.js");
		calendarLocaleMap.put("bg", "calendar-bg.js");
		calendarLocaleMap.put("big5", "calendar-big5.js");
		calendarLocaleMap.put("br", "calendar-br.js");
		calendarLocaleMap.put("ca", "calendar-ca.js");
		calendarLocaleMap.put("cs", "calendar-cs.js");
		calendarLocaleMap.put("da", "calendar-da.js");
		calendarLocaleMap.put("de", "calendar-de.js");
		calendarLocaleMap.put("du", "calendar-du.js");
		calendarLocaleMap.put("el", "calendar-el.js");
		calendarLocaleMap.put(DEFAULT_CALENDAR_LOCALE_CODE, "calendar-en.js");
		calendarLocaleMap.put("es", "calendar-es.js");
		calendarLocaleMap.put("fi", "calendar-fi.js");
		calendarLocaleMap.put("fr", "calendar-fr.js");
		calendarLocaleMap.put("he", "calendar-he.js");
		calendarLocaleMap.put("hr", "calendar-hr.js");
		calendarLocaleMap.put("hu", "calendar-hu.js");
		calendarLocaleMap.put("it", "calendar-it.js");
		calendarLocaleMap.put("ja", "calendar-ja.js");
		calendarLocaleMap.put("ko", "calendar-ko.js");
		calendarLocaleMap.put("lt", "calendar-lt.js");
		calendarLocaleMap.put("lv", "calendar-lv.js");
		calendarLocaleMap.put("no", "calendar-no.js");
		calendarLocaleMap.put("pl", "calendar-pl.js");
		calendarLocaleMap.put("pt", "calendar-pt.js");
		calendarLocaleMap.put("ro", "calendar-ro.js");
		calendarLocaleMap.put("ru", "calendar-ru.js");
		calendarLocaleMap.put("si", "calendar-si.js");
		calendarLocaleMap.put("sk", "calendar-sk.js");
		calendarLocaleMap.put("sp", "calendar-sp.js");
		calendarLocaleMap.put("sq", "calendar-al.js");
		calendarLocaleMap.put("sv", "calendar-sv.js");
		calendarLocaleMap.put("tr", "calendar-tr.js");
		calendarLocaleMap.put("ua", "calendar-ua.js");
		calendarLocaleMap.put("zh", "calendar-zh.js");
		nameMap = new HashMap<String, String>();
		nameMap.put(timeZoneIds[0], "International Date Line West");
		nameMap.put(timeZoneIds[1], "Midway Island, Samoa");
		nameMap.put(timeZoneIds[2], "Hawaii");
		nameMap.put(timeZoneIds[3], "Alaska");
		nameMap.put(timeZoneIds[4], "Pacific Time (US & Canada); Tijuana");
		nameMap.put(timeZoneIds[5], "Arizona");
		nameMap.put(timeZoneIds[6], "Chihuahua, La Pax, Mazatlan");
		nameMap.put(timeZoneIds[7], "Mountain Time (US & Canada)");
		nameMap.put(timeZoneIds[8], "Central America");
		nameMap.put(timeZoneIds[9], "Central Time (US & Canada)");
		nameMap.put(timeZoneIds[10], "Guadalajara, Mexico City, Monterrey");
		nameMap.put(timeZoneIds[11], "Saskatchewan");
		nameMap.put(timeZoneIds[12], "Bogota, Lima, Quito");
		nameMap.put(timeZoneIds[13], "Eastern Time (US & Canada)");
		nameMap.put(timeZoneIds[14], "Indiana (East)");
		nameMap.put(timeZoneIds[15], "Atlantic Time (Canada)");
		nameMap.put(timeZoneIds[16], "Caracas, La Paz");
		nameMap.put(timeZoneIds[17], "Santiago");
		nameMap.put(timeZoneIds[18], "Newfoundland");
		nameMap.put(timeZoneIds[19], "Brasilia");
		nameMap.put(timeZoneIds[20], "Buenos Aires, Georgetown");
		nameMap.put(timeZoneIds[21], "Greenland");
		nameMap.put(timeZoneIds[22], "Mid-Atlantic");
		nameMap.put(timeZoneIds[23], "Azores");
		nameMap.put(timeZoneIds[24], "Cape Verde Is.");
		nameMap.put(timeZoneIds[25], "Casablanca, Monrovia");
		nameMap.put(timeZoneIds[26],
				"Greenwich Mean Time : Dublin, Edinburgh, Lisbon, London");
		nameMap.put(timeZoneIds[27],
				"Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna");
		nameMap.put(timeZoneIds[28],
				"Belgrade, Bratislava, Budapest, Ljubljana, Prague");
		nameMap.put(timeZoneIds[29], "Brussels, Copenhagen, Madrid, Paris");
		nameMap.put(timeZoneIds[30], "Sarajevo, Skopje, Warsaw, Zagreb");
		nameMap.put(timeZoneIds[31], "West Central Africa");
		nameMap.put(timeZoneIds[32], "Athens, Istanbul, Minsk");
		nameMap.put(timeZoneIds[33], "Bucharest");
		nameMap.put(timeZoneIds[34], "Cairo");
		nameMap.put(timeZoneIds[35], "Harare, Pretoria");
		nameMap.put(timeZoneIds[36],
				"Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius");
		nameMap.put(timeZoneIds[37], "Jerusalem");
		nameMap.put(timeZoneIds[38], "Baghdad");
		nameMap.put(timeZoneIds[39], "Kuwait, Riyadh");
		nameMap.put(timeZoneIds[40], "Moscow, St. Petersburg, Volgograd");
		nameMap.put(timeZoneIds[41], "Nairobi");
		nameMap.put(timeZoneIds[42], "Tehran");
		nameMap.put(timeZoneIds[43], "Abu Dhabi, Muscat");
		nameMap.put(timeZoneIds[44], "Baku, Tbilisi, Muscat");
		nameMap.put(timeZoneIds[45], "Kabul");
		nameMap.put(timeZoneIds[46], "Ekaterinburg");
		nameMap.put(timeZoneIds[47], "Islamabad, Karachi, Tashkent");
		nameMap.put(timeZoneIds[48], "Chennai, Kolkata, Mumbai, New Dehli");
		nameMap.put(timeZoneIds[49], "Kathmandu");
		nameMap.put(timeZoneIds[50], "Almaty, Novosibirsk");
		nameMap.put(timeZoneIds[51], "Astana, Dhaka");
		nameMap.put(timeZoneIds[52], "Sri Jayawardenepura");
		nameMap.put(timeZoneIds[53], "Rangoon");
		nameMap.put(timeZoneIds[54], "Bangkok, Hanoi, Jakarta");
		nameMap.put(timeZoneIds[55], "Krasnoyarsk");
		nameMap.put(timeZoneIds[56], "Beijing, Chongqing, Hong Kong, Urumqi");
		nameMap.put(timeZoneIds[57], "Irkutsk, Ulaan Bataar");
		nameMap.put(timeZoneIds[58], "Kuala Lumpur, Singapore");
		nameMap.put(timeZoneIds[59], "Perth");
		nameMap.put(timeZoneIds[60], "Taipei");
		nameMap.put(timeZoneIds[61], "Osaka, Sapporo, Tokyo");
		nameMap.put(timeZoneIds[62], "Seoul");
		nameMap.put(timeZoneIds[63], "Yakutsk");
		nameMap.put(timeZoneIds[64], "Adelaide");
		nameMap.put(timeZoneIds[65], "Darwin");
		nameMap.put(timeZoneIds[66], "Brisbane");
		nameMap.put(timeZoneIds[67], "Canberra, Melbourne, Sydney");
		nameMap.put(timeZoneIds[68], "Guam, Port Moresby");
		nameMap.put(timeZoneIds[69], "Hobart");
		nameMap.put(timeZoneIds[70], "Vladivostok");
		nameMap.put(timeZoneIds[71], "Magadan, Solomon Is., New Caledonia");
		nameMap.put(timeZoneIds[72], "Auckland, Wellington");
		nameMap.put(timeZoneIds[73], "Fiji, Kamchatka, Marshall Is.");
		nameMap.put(timeZoneIds[74], "Nuku'alofa");
	}

	public static class LocaleProviderWrapper implements LocaleProvider {

		public Locale getLocale() {
			return locale;
		}

		private Locale locale;

		public LocaleProviderWrapper(Locale locale) {
			this.locale = locale;
		}
	}

	private LocaleUtils() {
	}

	public static Locale localeCodeToLocale(String localeCode) {
		Locale locale = null;
		if (localeCode != null && localeCode.length() > 0) {
			String language = null;
			String country = null;
			String variant = null;
			StringTokenizer tokenizer = new StringTokenizer(localeCode, "_");
			if (tokenizer.hasMoreTokens()) {
				language = tokenizer.nextToken();
				if (tokenizer.hasMoreTokens()) {
					country = tokenizer.nextToken();
					if (tokenizer.hasMoreTokens())
						variant = tokenizer.nextToken();
				}
			}
			locale = new Locale(language, country == null ? "" : country,
					variant == null ? "" : variant);
		}
		return locale;
	}

	public static Locale[] getAvailableLocales() {
		Locale locales[] = Locale.getAvailableLocales();
		Arrays.sort(locales, OfficeComparators.LOCALE);
		return locales;
	}

	public static boolean isValidCharacterEncoding(String encoding) {
		boolean valid = true;
		try {
			"".getBytes(encoding);
		} catch (Exception e) {
			valid = false;
		}
		return valid;
	}

	public static Map getISO639LanguageMap() {
		return languageMap;
	}

	public static String[][] getTimeZoneList() {
		Locale officeLocale = OfficeGlobals.getLocale();
		String timeZoneList[][] = (String[][]) timeZoneLists.get(officeLocale);
		if (timeZoneList == null) {
			Date now = new Date();
			String timeZoneIDs[] = timeZoneIds;
			timeZoneList = new String[timeZoneIDs.length][2];
			for (int i = 0; i < timeZoneList.length; i++) {
				String zoneID = timeZoneIDs[i];
				timeZoneList[i][0] = zoneID;
				timeZoneList[i][1] = getTimeZoneName(zoneID, now, officeLocale);
			}

			timeZoneLists.put(officeLocale, timeZoneList);
		}
		return timeZoneList;
	}

	public static Locale getUserLocale(HttpServletRequest request, UserBean user) {
		return getUserLocale(request, user, true);
	}

	public static Locale getUserLocale(HttpServletRequest request,
			UserBean user, boolean useDefault) {
		Locale locale = null;
		if (OfficeGlobals.getOfficeBooleanProperty(
				"skin.default.usersChooseLocale", true))
			if (user != null
					&& user.getProperties().get("officeLocale") != null)
				locale = localeCodeToLocale((String) user.getProperties().get(
						"officeLocale"));
			else
				locale = getLocaleFromRequestHeader(request);
		if (locale != null)
			return locale;
		if (useDefault)
			return OfficeGlobals.getLocale();
		else
			return null;
	}

	public static TimeZone getTimeZone(HttpServletRequest request, UserBean user) {
		TimeZone timeZone = OfficeGlobals.getTimeZone();
		String timeZoneID = null;
		if (user != null)
			timeZoneID = (String) user.getProperties().get("officeTimeZoneID");
		else if (request != null) {
			Cookie cookie = CookieUtils.getCookie(request, "officeTimeZoneID");
			if (cookie != null)
				timeZoneID = cookie.getValue();
		}
		if (timeZoneID != null)
			timeZone = TimeZone.getTimeZone(timeZoneID);
		return timeZone;
	}

	private static String getTimeZoneName(String zoneID, Date now, Locale locale) {
		TimeZone zone = TimeZone.getTimeZone(zoneID);
		StringBuffer buf = new StringBuffer();
		int offset = zone.getRawOffset();
		if (zone.inDaylightTime(now) && zone.useDaylightTime())
			offset += 0x36ee80;
		buf.append("(");
		if (offset < 0)
			buf.append("GMT-");
		else
			buf.append("GMT+");
		offset = Math.abs(offset);
		int hours = offset / 0x36ee80;
		int minutes = (offset % 0x36ee80) / 60000;
		buf.append(hours).append(":");
		if (minutes < 10)
			buf.append("0").append(minutes);
		else
			buf.append(minutes);
		buf.append(") ");
		if (DEFAULT_CALENDAR_LOCALE_CODE.equals(locale.getLanguage())) {
			String name = (String) nameMap.get(zoneID);
			if (name == null)
				name = zoneID;
			buf.append(name);
		} else {
			buf.append(zone.getDisplayName(true, 1, locale).replace('_', ' ')
					.replace('/', ' '));
		}
		return buf.toString();
	}

	public static String getLocalizedString(String key) {
		Locale locale = OfficeGlobals.getLocale();
		String s = OfficeGlobals.getLocalizedOfficeProperty(key, locale);
		if (s == null)
			s = getLocalizedString(key, locale, null);
		return s;
	}

	public static String getLocalizedString(String key, Locale locale) {
		String s = OfficeGlobals.getLocalizedOfficeProperty(key, locale);
		if (s == null)
			s = getLocalizedString(key, locale, null);
		return s;
	}

	public static String getLocalizedString(String key, List arguments) {
		return getLocalizedString(key, OfficeGlobals.getLocale(), arguments);
	}

	public static String getLocalizedString(String key, Locale locale,
			List arguments) {
		if (key == null)
			throw new NullPointerException("i18n key cannot be null");
		if (locale == null)
			locale = OfficeGlobals.getLocale();
		OfficeTextProvider provider = new OfficeTextProvider(LocaleUtils.class,
				new LocaleProviderWrapper(locale));
		String value = provider.getText(getEditionizedKey(key), arguments);
		if (value == null)
			value = "";
		return value;
	}

	public static String getLocalizedNumber(long number) {
		return NumberFormat.getInstance().format(number);
	}

	public static String getLocalizedNumber(long number, Locale locale) {
		return NumberFormat.getInstance(locale).format(number);
	}

	public static String getLocalizedNumber(double number) {
		return NumberFormat.getInstance().format(number);
	}

	public static String getLocalizedNumber(double number, Locale locale) {
		return NumberFormat.getInstance(locale).format(number);
	}

	public static ResourceBundle getResourceBundle(String baseName) {
		ResourceBundle bundle = null;
		try {
			bundle = ResourceBundle.getBundle(baseName, OfficeGlobals
					.getLocale());
		} catch (MissingResourceException mre) {
			log.error((new StringBuilder()).append(
					"Unable to load resource bundle: ").append(baseName)
					.toString());
		}
		return bundle;
	}

	public static String getLocalizedString(String key, String pluginName) {
		return getLocalizedString(key, pluginName, null);
	}

	public static String getLocalizedString(String key, String pluginName,
			List arguments) {
		if (key == null)
			throw new NullPointerException("i18n key cannot be null");
		return key;
	}

	public static String getLocalizedString(String key, Locale locale,
			List arguments, ResourceBundle bundle) {
		if (key == null)
			throw new NullPointerException("Key cannot be null");
		if (locale == null)
			locale = OfficeGlobals.getLocale();
		String value;
		try {
			value = bundle.getString(getEditionizedKey(key));
			if (arguments != null) {
				MessageFormat messageFormat = new MessageFormat("");
				messageFormat.setLocale(bundle.getLocale());
				messageFormat.applyPattern(value);
				try {
					java.text.Format formats[] = messageFormat.getFormats();
					for (int i = 0; i < formats.length; i++) {
						java.text.Format format = formats[i];
						if (format == null)
							continue;
						Object val;
						if (format instanceof DateFormat) {
							if (arguments.size() <= i)
								continue;
							val = arguments.get(i);
							if (!(val instanceof String))
								continue;
							DateFormat dateFmt = (DateFormat) format;
							try {
								val = dateFmt.parse((String) val);
								arguments.set(i, val);
							} catch (ParseException e) {
								log.error(e);
							}
							continue;
						}
						if (!(format instanceof NumberFormat)
								|| arguments.size() <= i)
							continue;
						val = arguments.get(i);
						if (!(val instanceof String))
							continue;
						NumberFormat nbrFmt = (NumberFormat) format;
						try {
							val = nbrFmt.parse((String) val);
							arguments.set(i, val);
						} catch (ParseException e) {
							log.error(e);
						}
					}

					value = messageFormat
							.format(((Object) (arguments.toArray())));
				} catch (IllegalArgumentException e) {
					log
							.error((new StringBuilder())
									.append(
											"Unable to format resource string for key: ")
									.append(key).append(
											", argument type not supported")
									.toString());
					value = "";
				}
			}
		} catch (MissingResourceException mre) {
			log.warn((new StringBuilder()).append("Missing resource for key: ")
					.append(key).append(" in locale ")
					.append(locale.toString()).toString());
			value = "";
		}
		return value;
	}

	public static String getCalendarFileName(Locale locale) {
		if (locale != null
				&& calendarLocaleMap.containsKey(locale.getLanguage()))
			return (String) calendarLocaleMap.get(locale.getLanguage());
		else
			return (String) calendarLocaleMap.get(DEFAULT_CALENDAR_LOCALE_CODE);
	}

	public static String getCalendarOverrideFormat(Locale locale) {
		if (locale != null) {
			if (calendarLocaleFormatMap.containsKey(locale.toString())) {
				return (String) calendarLocaleFormatMap.get(locale.toString());
			} else {
				String jsFormatString = jsFormatString(locale);
				calendarLocaleFormatMap.put(locale.toString(), jsFormatString);
				return jsFormatString;
			}
		} else {
			return DEFAULT_JS_DATE_FORMAT;
		}
	}

	private static String jsFormatString(Locale locale) {
		DateFormat dateFormat = DateFormat.getDateInstance(3, locale);
		String jsFormat = DEFAULT_JS_DATE_FORMAT;
		try {
			String symbols = ((SimpleDateFormat) dateFormat).toPattern();
			if (symbols.startsWith("d")) {
				if (symbols.contains("/"))
					jsFormat = DEFAULT_JS_DATE_FORMAT;
				else if (symbols.contains("."))
					jsFormat = "%d.%m.%Y";
				else if (symbols.contains("-"))
					jsFormat = "%d-%m-%Y";
			} else if (symbols.startsWith("M")) {
				if (symbols.contains("/"))
					jsFormat = "%m/%d/%Y";
				else if (symbols.contains("."))
					jsFormat = "%m.%d.%Y";
				else if (symbols.contains("-"))
					jsFormat = "%m-%d-%Y";
			} else if (symbols.startsWith("y"))
				if (symbols.contains("/"))
					jsFormat = "%Y/%m/%d";
				else if (symbols.contains("."))
					jsFormat = "%Y.%m.%d";
				else if (symbols.contains("-"))
					jsFormat = "%Y-%m-%d";
		} catch (ClassCastException e) {
		}
		return jsFormat;
	}

	public static String getLocalizedDateFormatPattern(Locale locale) {
		DateFormat dateFormat;
		if (locale == null)
			locale = OfficeGlobals.getLocale();
		try {
			dateFormat = DateFormat.getDateInstance(3, locale);
			return ((SimpleDateFormat) dateFormat).toLocalizedPattern();
		} catch (ClassCastException e) {
			return "MM/dd/yy";
		}
	}

	public static List getCandidateLocales(Locale locale) {
		if (cachedCandidateLocales.containsKey(locale))
			return (List) cachedCandidateLocales.get(locale);
		List results = new ArrayList();
		results.add(locale);
		if (locale.getVariant().length() > 0)
			results.add(new Locale(locale.getLanguage(), locale.getCountry()));
		if (locale.getCountry().length() > 0)
			results.add(new Locale(locale.getLanguage()));
		results = Collections.unmodifiableList(results);
		cachedCandidateLocales.put(locale, results);
		return results;
	}

	public static Locale getLocaleFromRequestHeader(HttpServletRequest request) {
		if (request == null)
			return null;
		String header = request.getHeader("Accept-Language");
		if (header == null)
			return null;
		List locales = new ArrayList();
		String localeCodes[] = header.split(",");
		String arr$[] = localeCodes;
		int len$ = arr$.length;
		for (int i$ = 0; i$ < len$; i$++) {
			String localeCode = arr$[i$];
			localeCode = localeCode.replace('-', '_').trim();
			if (localeCode.equals("*"))
				continue;
			int qualityIndex = localeCode.indexOf(";");
			if (qualityIndex > -1)
				locales.add(localeCodeToLocale(localeCode.substring(0,
						qualityIndex)));
			else
				locales.add(localeCodeToLocale(localeCode));
		}

		Iterator it = locales.iterator();
		Locale locale;
		label0: do
			if (it.hasNext()) {
				locale = (Locale) it.next();
				Iterator it1 = getCandidateLocales(locale).iterator();
				Locale candidate;
				do {
					if (!it1.hasNext())
						continue label0;
					candidate = (Locale) it1.next();
				} while (!SUPPORTED_LOCALES.contains(candidate));
				break;
			} else {
				return null;
			}
		while (true);
		return locale;
	}

	private static List getSupportedLocales() {
		List results = new ArrayList();
		StringBuilder builder = new StringBuilder();
		Locale arr$[] = Locale.getAvailableLocales();
		int len$ = arr$.length;
		for (int i$ = 0; i$ < len$; i$++) {
			Locale locale = arr$[i$];
			builder.setLength(0);
			builder.append(I18N_PROPERTY_FILE_PREFIX).append("_").append(
					locale.toString()).append(".properties");
			if (null != ClassUtilsStatic.getResource(builder.toString(),
					LocaleUtils.class))
				results.add(locale);
		}

		return results;
	}

	public static String parseLocaleCodeFromPropertyFilename(String name) {
		Pattern pattern = Pattern
				.compile(".*?(_\\D\\D)?(_\\D\\D)\\.properties$");
		Matcher matcher = pattern.matcher(name);
		String result;
		if (matcher.find()) {
			if (matcher.group(1) == null)
				result = matcher.group(2);
			else
				result = (new StringBuilder()).append(matcher.group(1)).append(
						matcher.group(2)).toString();
		} else {
			return null;
		}
		return result.substring(1, result.length());
	}

	public static Map getContainerKeys() {
		Map keys = new HashMap();
		String resources[] = { "office_i18n_en", "office_setup", "office_admin" };
		String arr$[] = resources;
		int len$ = arr$.length;
		label0: for (int i$ = 0; i$ < len$; i$++) {
			String resource = arr$[i$];
			Properties props = new Properties();
			try {
				props.load(ClassUtilsStatic
						.getResourceAsStream((new StringBuilder()).append("/")
								.append(resource).append(".properties")
								.toString()));
				Iterator it = props.keySet().iterator();
				do {
					String prop;
					do {
						if (!it.hasNext())
							continue label0;
						Object o = it.next();
						prop = (String) o;
					} while (!prop.endsWith(".internal")
							|| !props.containsKey((new StringBuilder()).append(
									prop.substring(0, prop.length() - 9))
									.append(".external").toString()));
					keys.put(prop.substring(0, prop.length() - 9), null);
				} while (true);
			} catch (IOException e) {
				log.warn((new StringBuilder()).append(
						"error loading property file: ").append(resource)
						.append(":").append(e.toString()).toString());
			}
		}

		return keys;
	}

	private static String getEditionizedKey(String key) {
		if (I18N_EDITION_KEYS.containsKey(key))
			// if
			// (JiveApplication.getContext().getLicenseManager().isExternal())
			// key = (new StringBuilder()).append(key).append(".external")
			// .toString();
			// else
			key = (new StringBuilder()).append(key).append(".internal")
					.toString();
		return key;
	}

}
